package com.technique.api.business.controller;

import java.security.Principal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.technique.api.business.dao.RequirementDao;
import com.technique.api.business.dao.RequirementTomeDao;
import com.technique.api.dao.entity.Place;
import com.technique.api.dao.entity.Requirement;
import com.technique.api.dao.entity.RequirementTome;
import com.technique.api.dao.entity.RequirementTomeExample;
import com.technique.api.model.User;
import com.technique.api.place.dao.PlaceDao;
import com.technique.api.shop.controller.ShopService;
import com.technique.api.user.FeifanUserService;
import com.technique.api.util.LoggerUtil;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

@Controller
@RequestMapping("/api/requirement")
public class RequirementController {
	ExecutorService executor = new ThreadPoolExecutor(5, 10, 500, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(100), Executors.defaultThreadFactory(),new ThreadPoolExecutor.DiscardOldestPolicy());
	
	@Autowired
	private ShopService shopService;
	@Autowired
	private RequirementDao requirementDao;
	
	@Autowired
	private RequirementTomeDao requirementTomeDao;
	
	@Autowired
	private PlaceDao placeDao;
	
	@Autowired
	private FeifanUserService feifanUserService;
	
	@ResponseBody  
	@RequestMapping("/to_me")
	public String to_me(Principal principal){
		User user  = this.feifanUserService.getUserInfo(principal);
		if(user == null){
			throw new IllegalArgumentException("user info is missing");
		}
		long uid = user.getUid();
		JSONObject result  =new JSONObject() ;
		JSONArray placesJson = new JSONArray();
		RequirementTomeExample example = new RequirementTomeExample();
		example.createCriteria().andToUidEqualTo(uid).andStateIn(Arrays.asList(new Short[]{(short)1,(short)2}));
		example.setOrderByClause(" create_date desc");
		List<RequirementTome> tomeList = this.requirementTomeDao.selectByExample(example);
		if(tomeList == null || tomeList.isEmpty()){
			result.put("requirement_list", placesJson);
			return result.toString();
		}
		
		List<Requirement> requirements = getRequirement(tomeList);
				
		Map<Long,Place> placeMap = getPlaceMap(requirements);
		
		for(Requirement requirement: requirements){
			JSONObject json = new JSONObject();
			json.put("id", requirement.getId());
			json.put("budget", requirement.getBudget());
			json.put("planStartDate", requirement.getPlanStartDate().getTime());
			json.put("planTripDays", requirement.getPlanTripDays());
			json.put("userCount", requirement.getUserCount());
			json.put("publishDate", requirement.getPublishDate().getTime());
			JSONArray places = new JSONArray();

			for(String placeId:requirement.getTargetPlaces().split(",")){
				JSONObject placeJson = new JSONObject();
				if(placeMap.get(Long.valueOf(placeId)) ==null){
					continue;
				}
				Place place = placeMap.get(Long.valueOf(placeId));
				placeJson.put("id", place.getId());
				placeJson.put("cnName", place.getCnName());
				placeJson.put("enName", place.getEnName());
				places.add(placeJson);
			}

			json.put("places", places);
			placesJson.add(json);

		}
		result.put("requirement_list", placesJson);
		
		return result.toString();
	}
	
	private Map<Long, Place> getPlaceMap(List<Requirement> requirements) {
		Map<Long,Place> result = new HashMap<Long,Place>();
		Set<Long> placeIds = new HashSet<Long>();
		for(Requirement requirement: requirements){
			String placeIdsStr = requirement.getTargetPlaces();
			if(StringUtils.isEmpty(placeIdsStr))
				continue;
			String[] placeIdsStrArr = placeIdsStr.split(",");
			for(String placeIdStr:placeIdsStrArr){
				placeIds.add(Long.valueOf(placeIdStr));
			}
		}
		List<Future<Place>> futures = new ArrayList<Future<Place>>();

		for(final long placeId: placeIds){
			Future<Place> placeFuture = this.executor.submit(new Callable<Place>(){
				@Override
				public Place call() throws Exception {
					return placeDao.selectByPrimaryKey(placeId);
				}
			});
			futures.add(placeFuture);
		}
		
		for(Future<Place> future: futures){
			try {
				Place place = future.get(100, TimeUnit.MILLISECONDS);
				if(place!=null)
					result.put(place.getId(), place);
			} catch (Exception e) {
				LoggerUtil.error("get requirement fail",e);
			}
		}
		return result;
	}

	private static class RequirementWrapper{
		private long id;
		
		private long uid;
		
		private Date planStartDate;
		private Date publishDate;
		private List<Place> places;
		
		
		
	}
	
	
	
	private List<Requirement> getRequirement(List<RequirementTome> tomeList) {
		List<Requirement> requirementList = new ArrayList<Requirement>();
		//1. 取出需求单；
		List<Future<Requirement>> futures = new ArrayList<Future<Requirement>>();
		for(RequirementTome tome: tomeList){
			final long id = tome.getId();
			Future<Requirement> requirement = this.executor.submit(new Callable<Requirement>(){
				@Override
				public Requirement call() throws Exception {
					return requirementDao.selectByPrimaryKey(id);
				}
			});
			futures.add(requirement);
		}
		
		for(Future<Requirement> future: futures){
			try {
				Requirement requirement = future.get(100, TimeUnit.MILLISECONDS);
				if(requirement!=null)
					requirementList.add(requirement);
			} catch (Exception e) {
				LoggerUtil.error("get requirement fail",e);
			}
		}
		
		return requirementList;
	}
	
	
	@ResponseBody
	@RequestMapping(method= RequestMethod.POST,value="/publish")  
	public String publishRequirement(
			   Principal principal,
			   int type,
			   String location_ids,
			   int adult_count,
			   int children_count,
			   int trip_days,
			   long plan_start_date,
			   long plan_end_date,
			   boolean is_book_hotel,
			   int hotel_rank,
			   int location,
			   boolean follow_film ,
			   int car_rank  
			){
		
		
		
		return "{\"result\":\"true\"}";
	}

	
	@ResponseBody
	@RequestMapping(method=RequestMethod.GET,value="by_me")
	public String byMe(){
		JSONObject json = new JSONObject();
		
		JSONArray requirements = new JSONArray();
		
		JSONObject req= new JSONObject();
		req.put("pic", "{\"small\":\"\",\"middle\":\"\",\"large\":\"\"}");
		req.put("id", 1111);
		req.put("title","法意瑞三国游");
		requirements.add(req);
		requirements.add(req);
		requirements.add(req);

		json.put("requirements", requirements);
		
		return json.toString();
	}
	
	@ResponseBody
	@RequestMapping(method=RequestMethod.GET,value="show")
	public String show(){
		JSONObject json = new JSONObject();
		json.put("id", 10001);
		
		
		JSONArray destinations = new JSONArray();
		JSONObject country = new JSONObject();
		country.put("id", 10001);
		country.put("name", "法国");
		JSONArray places = new JSONArray();
		places.add(JSONObject.fromObject("{\"id\":\"10001\",\"name\":\"尼斯\"}"));
		places.add(JSONObject.fromObject("{\"id\":\"10002\",\"name\":\"巴黎\"}"));
		places.add(JSONObject.fromObject("{\"id\":\"10003\",\"name\":\"摩纳哥\"}"));
		country.put("places", places);
		destinations.add(country);
		
		country = new JSONObject();
		country.put("id", 10002);
		country.put("name", "德国");
		places = new JSONArray();
		places.add(JSONObject.fromObject("{\"id\":\"10001\",\"name\":\"慕尼黑\"}"));
		places.add(JSONObject.fromObject("{\"id\":\"10002\",\"name\":\"法兰克福\"}"));
		country.put("places", places);
		destinations.add(country);

		
		country.put("places", places);
		json.put("destinations", destinations);
		json.put("adult_count", 2);
		json.put("children_count", 1);
		json.put("trip_days", 3);
		json.put("plan_start_date", 18012312);
		json.put("plan_end_date", 18014312);
		json.put("is_book_hotel", true);
		json.put("hotel_rank", 5);
		json.put("location", 1);
		json.put("follow_film", true);
		json.put("car_rank", 1);		
		return json.toString();
	}
	
	@ResponseBody
	@RequestMapping(method= RequestMethod.POST,value="/publish_")  
	public String publishRequirement_(Principal principal,String targetPlaceIds,int userCount,long planStartDate,String customRequirement,int budget,int planTripDayCount,String ext){
		User user  = this.feifanUserService.getUserInfo(principal);
		if(user == null){
			throw new IllegalArgumentException("user info is missing");
		}
		long fromUid = user.getUid();
		if(StringUtils.isBlank(targetPlaceIds)){
			throw new IllegalArgumentException("targetPlaceIds cannot be null");
		}
		
		try{
		//1. 校验地区是否合法
		List<Long> placeIds = new ArrayList<Long>();
		
		String[] targetIds = targetPlaceIds.split(",");
		
		for(String idStr : targetIds){
			placeIds.add(Long.valueOf(idStr));
		}
		
		//2. 新增用户需求
		Requirement requirement = new Requirement();
		requirement.setTargetPlaces(targetPlaceIds);
		requirement.setBudget(budget);
		requirement.setExt(ext);
		requirement.setPlanTripDays(planTripDayCount);
		requirement.setPlanStartDate(new Date(planStartDate));
		requirement.setPublishDate(new Date());
		requirement.setUid(fromUid);
		requirement.setUserCount(userCount);
		requirement.setCustomRequirement(customRequirement);
		this.requirementDao.insert(requirement);
		
		long reqId = requirement.getId();
		
		System.out.println(reqId);
		
		//3. 获取所有已经订阅该地区的商户
		Map<Long,List<Long>> map = this.shopService.getRegisterShopByPlacesId(placeIds);
		
		
		Set<Long> shops = new HashSet<Long>();
		//4. 同步推送需求
		if(map!=null){
			for(Entry<Long,List<Long>> entry: map.entrySet()){
				if(entry.getValue() == null || entry.getValue().isEmpty()){
					continue;
				}
				
				for(Long uid: entry.getValue()){
					if(!shops.contains(uid)){
						RequirementTome requirementTome = new RequirementTome();
						requirementTome.setId(reqId);
						requirementTome.setToUid(uid);
						requirementTome.setState((short)1);
						requirementTome.setCreateDate(new Date());
						this.requirementTomeDao.insert(requirementTome);
						shops.add(uid);
					}
				}
				
			}
		}
		
			return "{\"result\":\"true\"}";
		}catch(Exception e){
			LoggerUtil.error("exception",e);
			return "{\"result\":\"false\"}";
		}
	}

	

}
